package com.lqk.java8.streamAPI3;

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 终止操作
 */
public class StreamAPI3 {
    List<Employee> emps= Arrays.asList(
            new Employee("001", "张三", 18, 9999, Employee.Status.FREE),
            new Employee("002", "李四", 29, 8888,Employee.Status.BUSY),
            new Employee("003", "王二", 36, 10000,Employee.Status.VOCATION),
            new Employee("004", "麻子", 38, 12000,Employee.Status.BUSY)
    );
    /**
     * 查找与匹配
     *      allMatch--检查是否匹配所有元素            返回boolean
     *      anyMatch--检查是否至少匹配一个元素        返回boolean
     *      noneMatch--检查是否有匹配的元素          返回boolean
     *      findFirst--返回第一个元素
     *      findAny--返回当前流中的任意元素
     *      count--返回流中元素的总个数
     *      max--返回流中最大值
     *      min--返回流中最小值
     */
    @Test
    public void test1(){
        boolean b = emps.stream()
                .allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b);
        System.out.println("--------------------------");
        boolean b1 = emps.stream()
                .anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b1);
        System.out.println("--------------------------");
        boolean b2 = emps.stream()
                .noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
        System.out.println(b2);
        System.out.println("--------------------------");
        Optional<Employee> first = emps.stream()
                .sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary()))
                .findFirst();
        System.out.println(first.get());
        System.out.println("--------------------------");
        Optional<Employee> any = emps.parallelStream()  //并行流
                .filter((e) -> e.getStatus().equals(Employee.Status.FREE))
                .findAny();
        System.out.println(any.get());

    }
    @Test
    public void test2(){
        long count = emps.stream()
                .count();
        System.out.println(count);
        System.out.println("--------------------------");
        Optional<Employee> max = emps.stream()
                .max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(max.get());
        System.out.println("--------------------------");
        Optional<Double> aDouble = emps.stream()
                .min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
                .map(Employee::getSalary);
        System.out.println(aDouble.get());
    }

    /**
     * 归约
     *      reduce(T identity, BinaryOperator)/reduce(BinaryOperator)--可以将流中元素反复结合起来, 得到一个值
     */
    @Test
    public void test3(){
        List<Integer> list=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum = list.stream()
                .reduce(0, (x, y) -> x + y);
        System.out.println(sum);
        System.out.println("--------------------------------");
        Optional<Double> salary = emps.stream()
                .map(Employee::getSalary)
                .reduce(Double::sum);
        System.out.println(salary.get());
    }
    /**
     * 收集
     *      collect--将流转换成其他形式, 接收一个Collector接口的实现, 用于给stream中元素做汇总的方法
     */
    @Test
    public void test4(){
        List<String> list = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toList());
        list.forEach(System.out::println);
        System.out.println("--------------------------------");
        Set<String> set = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toSet());
        set.forEach(System.out::println);
        System.out.println("--------------------------------");
        HashSet<String> hashSet = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.toCollection(HashSet::new));
        hashSet.forEach(System.out::println);

    }
    @Test
    public void test5(){
        //总数
        Long count = emps.stream()
                .collect(Collectors.counting());
        System.out.println(count);
        System.out.println("--------------------------------");
        //平均值
        Double avg = emps.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
        System.out.println(avg);
        System.out.println("--------------------------------");

        //总和
        Double sum = emps.stream()
                .collect(Collectors.summingDouble(Employee::getSalary));
        System.out.println(sum);

        System.out.println("--------------------------------");
        //最大值
        Optional<Employee> max = emps.stream()
                .collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(max.get());

        System.out.println("--------------------------------");

        //最小值
        Optional<Employee> min = emps.stream()
                .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
        System.out.println(min.get());

        System.out.println("--------------------------------");

    }

    //分组
    @Test
    public void test6(){
        Map<Employee.Status, List<Employee>> group = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus));
        // 1. entrySet遍历，在键和值都需要时使用（最常用）
        for (Map.Entry<Employee.Status, List<Employee>> entry : group.entrySet()) {
            System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
        }

        System.out.println("----------------------------");

        // 2. 通过keySet或values来实现遍历,性能略低于第一种方式
        // 遍历map中的值
        for (List<Employee> value : group.values()) {
            System.out.println("value = " + value);
        }

        System.out.println("----------------------------");

        // 遍历map中的键
        for (Employee.Status key : group.keySet()) {
            System.out.println("key = " + key);
        }

        System.out.println("----------------------------");

        // 3. 使用Iterator遍历
        Iterator<Map.Entry<Employee.Status, List<Employee>>> it = group.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Employee.Status, List<Employee>> entry = it.next();
            System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue());
        }

        System.out.println("----------------------------");

        // 4. java8 Lambda
        // java8提供了Lambda表达式支持，语法看起来更简洁，可以同时拿到key和value，
        // 不过，经测试，性能低于entrySet,所以更推荐用entrySet的方式
        group.forEach((key, value) -> {
            System.out.println(key + ":" + value);
        });

    }

    //多级分组
    @Test
    public void test7(){
        Map<Employee.Status, Map<String, List<Employee>>> collect = emps.stream()
                .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
                    if (e.getAge() < 35) {
                        return "青年";
                    } else if (e.getAge() <= 50) {
                        return "中年";
                    } else {
                        return "老年";
                    }
                })));
        collect.forEach((key, value) -> {
            System.out.println(key + ":" + value);
        });
    }
    //分片(分区)
    @Test
    public void test8(){
        Map<Boolean, List<Employee>> part = emps.stream()
                .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 10000));
        part.forEach((key, value) -> {
            System.out.println(key + ":" + value);
        });
    }
    //求工资数, 工资和, 最小数, 平均数, 最大数
    @Test
    public void test9(){
        DoubleSummaryStatistics salary = emps.stream()
                .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(salary);
    }
    //将名字连成字符串返回, 用","隔开, 前后用"=="包裹
    @Test
    public void test10(){
        String str = emps.stream()
                .map(Employee::getName)
                .collect(Collectors.joining(",","==","=="));
        System.out.println(str);
    }

}
